/**
 * Copyright (c) 2014-2016 www.nryuncang.com. All Rights Reserved.
 */
package com.topisv.tms.service.print.impl;

import static com.google.common.base.Preconditions.checkArgument;

import java.io.StringReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXB;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.EdiOrderItem;
import com.topisv.tms.entity.ExpressConfigure;
import com.topisv.tms.entity.ExpressStyle;
import com.topisv.tms.entity.WarehouseAddress;
import com.topisv.tms.entity.work.WorkOrder;
import com.topisv.tms.entity.work.WorkTask;
import com.topisv.tms.mybatis.SqlMapDao;
import com.topisv.tms.repository.EdiOrderDao;
import com.topisv.tms.service.ExpressConfigureService;
import com.topisv.tms.service.WarehouseAddressService;
import com.topisv.tms.service.work.WorkOrderService;
import com.topisv.tms.service.work.WorkTaskService;
import com.topisv.tms.utils.ExpressUtil;
import com.topisv.tms.utils.yto.YTOResponse;

/**
 * 圆通打印
 *
 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
 * @version 0.0.16
 */
@Component
public class YTOPrintServiceImpl extends AbstractPrintService {

	private static final Logger logger = LoggerFactory.getLogger(YTOPrintServiceImpl.class);

	@Autowired
	private WorkTaskService workTaskService;
	@Autowired
	private ExpressConfigureService expressConfigureService;
	@Autowired
	private WarehouseAddressService warehouseAddressService;
	@Autowired
	private SqlMapDao sqlMapDao;
	@Autowired
	private WorkOrderService workOrderService;
	@Autowired
	private EdiOrderDao ediOrderDao;
	
	@SuppressWarnings("unchecked")
    @Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public List<EdiOrder> doGetExpressNo(List<String> orderNoList, ExpressStyle template, String taskCode)
			throws Exception {

		// 第一步:得到基础信息如作业任务，订单列表、仓库信息、配置信息
		WorkTask workTask = workTaskService.loadTaskByCode(taskCode);
		ExpressConfigure expressConfigure = expressConfigureService.findByWarehouseAndCompany(
				workTask.getWarehouseCode(), template.getLogisticsCompany().getCompanyCode());

		WarehouseAddress warehouseAddress = warehouseAddressService.findByWarehouseCode(workTask.getWarehouseCode());

		List<EdiOrder> ediOrderList = sqlMapDao.selectList("ediOrderMapper.getEdiOrderListByOrdeno", orderNoList);

		// 第二步:循环订单
		for (EdiOrder ediOrder : ediOrderList) {

			// 查询订单明细中的商品信息
			List<EdiOrderItem> ediOrderItemList = sqlMapDao.selectList("ediOrderItemMapper.getSkuInfoByOrdeno", ediOrder);

			WorkOrder workOrder = workOrderService.loadOrder(ediOrder.getBatchTaskCode(), ediOrder.getOrdeno());
			if (workOrder.getEbillNo() == null || "cbill".equals(workOrder.getBillType())
					|| !template.getLogisticsCompany().getCompanyCode().equals(workOrder.getExpressCompany())) {

				// 拼装报文
				Map<String, Object> xml = getYTOXml(ediOrder, ediOrderItemList, warehouseAddress, expressConfigure);
				String content =ExpressUtil.map2xmlBody(xml, "RequestOrder");
				logger.info("{}=圆通取单号报文={}", ediOrder.getOrdeno(), content);
				
				// 发送圆通接口,接收返回值
				String returnData = resturnYTOResult(content, expressConfigure);
				logger.info("{}=圆通取单号返回报文={}", ediOrder.getOrdeno(), returnData);
				
				YTOResponse result = new YTOResponse();
				//转换响应对象内容
				result = JAXB.unmarshal(new StringReader(returnData), YTOResponse.class);
				if (result == null ||  !"true".equals(result.getSuccess())) {
					logger.error("{}=请求圆通面单失败={}", ediOrder.getOrdeno(), result);
					throw new RuntimeException(ediOrder.getOrdeno() +"=请求圆通面单失败=" + result);
				}
				ediOrder.setMailNo(result.getOrderMessage().getMailNo());
				if(result.getOrderMessage() != null && result.getOrderMessage().getBigPen() != null) {
					ediOrder.setToShortAddress(result.getOrderMessage().getBigPen());
				}				
				ediOrder.setCacode(template.getLogisticsCompany().getCompanyCode());//快递公司代码
				ediOrder.setCaname(template.getLogisticsCompany().getCompanyName());//快递公司名称
			}
		}
		ediOrderDao.save(ediOrderList);
		return ediOrderList;
	}
	
	/**
	 * 发送圆通接口 post，返回请求结果
	 * 
	 *
	 * @param content
	 *            报文
	 * @param expressConfigure
	 *            配置信息
	 * @return
	 * @throws Exception
	 *             [参数说明]
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 * @version 0.0.16
	 */
	private String resturnYTOResult(String content, ExpressConfigure expressConfigure) throws Exception {
		String clientId = expressConfigure.getAccount();
		String partnerId = expressConfigure.getPassword();
		String url = expressConfigure.getUrl();
		
		// 校验id、密钥、请求地址
		checkArgument(StringUtils.isNotEmpty(clientId), String.format("YTO商家ID is empty"));
		checkArgument(StringUtils.isNotEmpty(partnerId), String.format("YTO商家密钥 is empty"));
		checkArgument(StringUtils.isNotEmpty(url), String.format("YTO请求地址 is empty"));
		
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		parameters.add(new BasicNameValuePair("logistics_interface", URLEncoder.encode(content, "UTF-8")));
		parameters.add(new BasicNameValuePair("data_digest",
				URLEncoder.encode(ExpressUtil.encryptBASE64(ExpressUtil.digestMD5(content + partnerId)), "UTF-8")));
		parameters.add(new BasicNameValuePair("clientId", URLEncoder.encode(clientId, "UTF-8")));
		return super.requestExpressNo(url, parameters);
	}

	/**
	 * YTO获取单号的报文
	 * 
	 *
	 * @param edirOrder
	 *            订单信息
	 * @param itemList
	 *            订单明细
	 * @param warehouseAddress
	 *            仓库地址
	 * @param expressConfigure
	 *            圆通配置信息
	 * @return [参数说明]
	 * @author <a href=mailto:zhangweize@nryuncang.com>zhangweize</a>
	 * @version 0.0.16
	 */
	private Map<String, Object> getYTOXml(EdiOrder edirOrder, List<EdiOrderItem> itemList,WarehouseAddress warehouseAddress, ExpressConfigure expressConfigure) {
		
		// 寄件人信息
		Map<String, Object> sender = new HashMap<>();
		sender.put("name", warehouseAddress.getContact());
		sender.put("postCode", "");
		sender.put("phone", "");
		sender.put("mobile", warehouseAddress.getMobile());
		sender.put("prov", warehouseAddress.getProvName());
		sender.put("city", warehouseAddress.getCityName());
		sender.put("address", warehouseAddress.getAddress());

		// 收件人信息
		Map<String, Object> receiver = new HashMap<>();
		receiver.put("name", edirOrder.getRecena());
		receiver.put("postCode", "");
		receiver.put("phone", edirOrder.getTeleph());
		receiver.put("mobile", edirOrder.getMobile());
		receiver.put("prov", edirOrder.getProvna());
		receiver.put("city", edirOrder.getCityna() + "," + edirOrder.getDistna());
		receiver.put("address", edirOrder.getAddres());

		// 商品明细
		List<Map<String, Object>> itemMapList = new ArrayList<>();
		double totalItemValue = 0.0;
		for (EdiOrderItem item : itemList) {
			Map<String, Object> itemMap = new HashMap<>();
			itemMap.put("itemName", item.getNam());
			itemMap.put("number", item.getQty());
			itemMap.put("itemValue", item.getPri());
			itemMapList.add(itemMap);
			totalItemValue += item.getPri();
		}

		Map<String, Object> map = new HashMap<String, Object>();
		// 商家代码
		map.put("clientID", expressConfigure.getAccount());
		// 物流公司ID
		map.put("logisticProviderID", "YTO");
		// 商家代码
		map.put("customerId", expressConfigure.getAccount());
		// 物流订单号
		map.put("txLogisticID", edirOrder.getOrdeno());
		// 业务交易号（可选)
		map.put("tradeNo", 1);
		// 总服务费[COD]
		map.put("totalServiceFee", 0);
		// 物流公司分润[COD]
		map.put("codSplitFee", 0);
		// 订单类型(0-COD,1-普通订单,2-便携式订单3-退货单)
		map.put("orderType", 1);
		// 服务类型(1-上门揽收, 2-次日达 4-次晨达 8-当日达,0-自己联系)。默认为0
		map.put("serviceType", 1);
		// 物流公司上门取货时间段通过“yyyy-MM-dd HH:mm s.S z”格式化，本文中所有时间格式相同。
		map.put("sendStartTime", edirOrder.getScheduleStartTime());
		map.put("sendEndTime", edirOrder.getScheduleEndTime());
		// 商品金额，包括优惠和运费，但无服务费
		map.put("goodsValue", edirOrder.getActuallyPaid());
		// 货物价值
		map.put("itemsValue", totalItemValue);
		// 保值金额（暂时没有使用，默认为0.0）
		map.put("insuranceValue", 0);
		// 备注
		map.put("remark", edirOrder.getRemark());
		map.put("deliverNo", 1);
		map.put("type", 1);
		// goodsValue+总服务费
		map.put("totalValue", 1);
		// 货物总重量
		map.put("itemsWeight", 1);
		map.put("packageOrNot", 1);
		map.put("orderSource", 1);
		map.put("sender", sender);
		map.put("receiver", receiver);
		map.put("items", itemMapList);
		return map;
	}

}
